package view;

import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.rmi.RemoteException;

import javax.swing.Box;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

import server.FirewallException;
import server.ReadWriteException;
import view.protocol.ProtocolFrame;

import controller.FirewallSession;

/**
 * Class is responsible for main frame.
 * Frame contains: 	menu - rules, logger, reg. expressions, exceptions, help 
 * 					standart buttons - help, finish
 */
public class MainFrame extends JFrame
{
	/**
	 * Serial version ID - for serialization
	 */
	private static final long serialVersionUID = 5032322274335194335L;

	/**
	 * server controller
	 */
	protected FirewallSession UI;
	
	/**
	 * Current shown main frame
	 */
	static private MainFrame frame = null;
	
	/**
	 * FW on/off button
	 */
	static protected final JButton onoff = new JButton();
	
	/**
	 * System status update timer
	 */
	static private StatusUpdateDynamicAction updateTimer = null;
	
	/**
	 * C'tor - Frame with specified controller is created:
	 * menu buttons and stadart buttons are defined. 
	 * @param ui	- the controller for the system actions
	 */
	private MainFrame(FirewallSession ui)
	{	
		/* Frame definition */
		super("FW Manager");
		UI = ui;
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setSize(Globals.mainFrameSize);
		setPanel();	
		
		setLocationRelativeTo(null);
	}
	
	/**
	 * Returns current frame if exists, else creates and registers it.
	 * @return main frame
	 */
	public static MainFrame getInstance(FirewallSession ui)
	{
		if(frame == null)
		{
			frame = new MainFrame(ui);
		    StatusBar.register(frame);
		}

		return frame;
	}
	
	/**
	 * Set the frame panels: menu, standart buttons
	 */
	private void setPanel()
	{	
		try {
			Settings.load();
		} catch (IOException e) {
			/* It's ok - default values */
		} catch (ClassNotFoundException e) {
			System.out.println("Class problem in reading");
			e.printStackTrace();
		}
		
		addPicture();
		addStandartButtons();
		addMenuButtons();
	}
	
	/**
	 * 
	 */
	private void addPicture()
	{
		//File f = new File("fw.jpg");	
		JPanel picture = new JPanel();		
		ImageIcon image = new ImageIcon("fw.jpg");
	
		JLabel background = new JLabel(image);

		background.setBounds(0, 0, image.getIconWidth(), image.getIconHeight());
		picture.add(background);
		picture.setVisible(true);

	    add(picture, BorderLayout.EAST);
	}

	/**
	 * Adds finish and cancel buttons.
	 * Builds their listeners.
	 */
	private void addStandartButtons() 
	{
		Box tableBox = Box.createHorizontalBox();
		
		JButton finish = new JButton("Finish");
		finish.setToolTipText("Close and save changes");
		JButton cancel = new JButton("Cancel");
		cancel.setToolTipText("Close without saving changes");
		
		tableBox.add(finish);
		tableBox.add(cancel);
		
		setLayout(new BorderLayout());    
		
	    
		finish.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) 
			{
				frameClose();
			}	  
		});
		  
		cancel.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) 
			{
				System.exit(0);				
			}	  
		});

	    add(tableBox, BorderLayout.SOUTH);
	}

	/**
	 * Adds Regular Expression, Rules, Logger, Error Reports, Help windows call buttons.
	 */
	private void addMenuButtons() 
	{
		JPanel menu = new JPanel(new GridLayout(7, 1));

		/* Regular Expression window call button and its listener */
		JButton pass = new JButton("Regular Expression");
		menu.add(pass);
		pass.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) 
			{
				ProtocolFrame frame = ProtocolFrame.getInstance(UI);
				frame.setVisible(true);
			}	  
		});
		
		/* Rules window call button and its listener */
		JButton rules = new JButton("Rules");
		menu.add(rules);
		rules.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) 
			{
				AbstractRulesFrame frame = null;
				
				/* Call the appropriate rules window */
				switch(Settings.userMode)
				{
				case STANDART:
					frame = RulesStandartFrame.getInstance(UI);
					break;
				case ADVANCED:
					frame = RulesAdvancedFrame.getInstance(UI);
					break;					
				}
				frame.setVisible(true);
			}	  
		});
		
		/* Logger window call button and its listener */
		JButton logger = new JButton("Logger");
		menu.add(logger);
		logger.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) 
			{
				LoggerFrame frame = LoggerFrame.getInctance(UI);
				frame.setVisible(true);
			}	  
		});		
	
		/* Error window call button and its listener */
		JButton error = new JButton("Exceptions List");
		menu.add(error);
		error.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) 
			{
				/* No need to create the frame - created in initialization */
				ErrorFrame.currentErrorFrame.setVisible(true);
			}	  
		});			
		
		/* Help window call button and its listener */
		JButton help = new JButton("Help");
		menu.add(help);
		help.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) 
			{
				/* No need to create the frame - created in initialization */
				HelpFrame.currentHelpFrame.ShowDesc(Globals.MAIN);
			}	  
		});		
		
		/* Turn FW on/off button and its listener */
		/* Turn FW on/off button status */
		try {
			if (UI.isOn())
			{
				onoff.setText("FW Off");
				onoff.setToolTipText("Turn off the FW");
			} else {
				onoff.setText("FW On");
				onoff.setToolTipText("Turn on the FW");
			}
			StatusBar.update();
		} catch (Exception e) {
			ErrorFrame.AddError("Connection problems: Failed getting FW state", new JFrame());
		}
		
		menu.add(onoff);	
		onoff.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) 
			{
				try {
					/* Call server for turning FW on/off according to the current status */
					if(StatusBar.fwTurnedOn == true)
					{
						UI.turnOff();
					}
					else
					{
						UI.turnOn();
					}
				} catch (RemoteException e) {
					ErrorFrame.AddError("Connection problems: Failed to turn on/off the firewall", new JFrame());
				} catch (FirewallException e) {
					ErrorFrame.AddError("Failed to turn on/off the firewall", new JFrame());
				} catch (ReadWriteException e) {
					ErrorFrame.AddError("Failed to turn on/off the firewall", new JFrame());
				}
			}	  
		});
	
	    add(menu, BorderLayout.WEST);
	 
		/* Time for sttaus update is initialized */
		updateTimer = new StatusUpdateDynamicAction(UI);
	}
	
	/**
	 * Actions on close operation.
	 */
	private void frameClose()
	{
		/* Save the settings */
		try {
			Settings.save();
		} catch (IOException e) {
			System.out.println("Output file isn't defined");
		}
		
		/* Stop active timer */
		if(updateTimer!= null)
		{
			updateTimer.stop();
		}
		
		System.gc();
		System.runFinalization();
		System.exit(0);
	}
	
	/**
	 * Actions on default close operation.
	 */
	public void dispose()
	{
		frameClose();
		super.dispose();
	}
}
